[BITS 32]

ISR_LENGTH equ 128		; Este valor debe ser el mismo que el definido en isr.h

; Esta macro crea un handler para una ISR que no crea codigo de error, 
; por lo que pushea un error code dummy

%macro ISR_NOERRCODE 1
global isr_%1
isr_%1:
    cli
    push dword 0				; Codigo de error dummy
    push dword %1				; Pushea el numero de interrupcion
    jmp isr_common_handler		; Voy al codigo comun para ISRs
%endmacro

; Esta macro crea un handler para una ISR que pushea codigo de error

%macro ISR_ERRCODE 1
global isr_%1
isr_%1:
    cli
    push dword %1				; Pushea el numero de interrupcion
    jmp isr_common_handler		; Voy al codigo comun de ISRs
%endmacro

; Esta macro crea un handler para una IRQ. El primer parametro es el
; numero de IRQ y el segundo es el numero de ISR a la que es mapeada

%macro IRQ 1
global isr_%1
isr_%1:
    cli
    push dword 0				; Codigo de error dummy
    push dword %1				; Numero de interrupcion
    jmp irq_common_handler    
%endmacro

; Creo todos los handlers

ISR_NOERRCODE  0 ; 0x00
ISR_NOERRCODE  1
ISR_NOERRCODE  2
ISR_NOERRCODE  3
ISR_NOERRCODE  4
ISR_NOERRCODE  5
ISR_NOERRCODE  6
ISR_NOERRCODE  7
ISR_ERRCODE    8 ; 0x08
ISR_NOERRCODE  9
ISR_ERRCODE   10
ISR_ERRCODE   11
ISR_ERRCODE   12
ISR_ERRCODE   13
ISR_ERRCODE   14
ISR_NOERRCODE 15
ISR_NOERRCODE 16 ; 0x10
ISR_ERRCODE   17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24 ; 0x18
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
IRQ           32 ; 0x20
IRQ           33
IRQ           34
IRQ           35
IRQ           36
IRQ           37
IRQ           38
IRQ           39
IRQ           40 ; 0x28
IRQ           41
IRQ           42
IRQ           43
IRQ           44
IRQ           45
IRQ           46
IRQ           47

IRQ          128 ; Para la syscall

extern isr_handler

; Variables para guardar el numero de excepcion y el error code

isr_number: 	dd 0x0
isr_error_code:	dd 0x0

; Handler comun de las excepciones. 

isr_common_handler:
    
    ; El estado de la pila en este momento es el siguiente...
    
    ; Numero Interrupcion
    ; Error Code
    ; EIP
    ; CS
    ; EFLAGS
    
    pop dword [isr_number]
    pop dword [isr_error_code]
    
    push ss
    push ds
    push es
    push fs
    push gs
    pusha				; Pushea eax, ecx, edx, ebx, esp, ebp, esi, edi

    ; :TODO: Estoy asumiendo que no se produjo cambios en el nivel
    ; de privilegio. Recordar que de producirse las posiciones de los
    ; valores en el stack cambian.
    
    ; El estado de la pila en este momento es el siguiente...
    
    ; EDI		(esp +  0 * 4) <- ESP actual
    ; ESI
    ; EBP
    ; ESP		(esp +  3 * 4)
    ; EBX
    ; EDX		(esp +  5 * 4)
    ; ECX
    ; EAX
    ; GS
    ; FS
    ; ES		(esp + 10 * 4)
    ; DS
    ; SS
    ; EIP
    ; CS
    ; EFLAGS	(esp + 15 * 4)
    ; 			(esp + 16 * 4) <- ESP antes de la interrupcion

    lea eax, [esp + 16 * 4]			; Cargo el valor del ESP de antes que se produzca la interrupcion
    mov [esp +  3 * 4], eax			; Guardo el valor original del ESP en la posicion correspondiente de la pila

    push esp						; Puntero a los datos
    push dword [isr_error_code]		; Codigo de error
    push dword [isr_number]			; Numero de interrupcion
    call isr_handler
    add esp, 3 * 4

    popa
    pop gs
    pop fs
    pop es
    pop ds
    add esp, 4		; Por el SS

    iret

extern irq_handler

; Variables para guardar el numero de excepcion y el error code

irq_number: 	dd 0x0
irq_error_code:	dd 0x0

; Handler comun de las interrupciones.

irq_common_handler:

    ; El estado de la pila en este momento es el siguiente...
    
    ; Numero Interrupcion
    ; Error Code
    ; EIP
    ; CS
    ; EFLAGS
    
    pop dword [irq_number]
    pop dword [irq_error_code]
    
    push ss
    push ds
    push es
    push fs
    push gs
    pusha				; Pushea eax, ecx, edx, ebx, esp, ebp, esi, edi

    ; :TODO: Estoy asumiendo que no se produjo cambios en el nivel
    ; de privilegio. Recordar que de producirse las posiciones de los
    ; valores en el stack cambian.
    
    ; El estado de la pila en este momento es el siguiente...
    
    ; EDI		(esp +  0 * 4) <- ESP actual
    ; ESI
    ; EBP
    ; ESP		(esp +  3 * 4)
    ; EBX
    ; EDX		(esp +  5 * 4)
    ; ECX
    ; EAX
    ; GS
    ; FS
    ; ES		(esp + 10 * 4)
    ; DS
    ; SS
    ; EIP
    ; CS
    ; EFLAGS	(esp + 15 * 4)
    ; 			(esp + 16 * 4) <- ESP antes de la interrupcion

    lea eax, [esp + 16 * 4]			; Cargo el valor del ESP de antes que se produzca la interrupcion
    mov [esp +  3 * 4], eax			; Guardo el valor original del ESP en la posicion correspondiente de la pila

    push esp						; Puntero a los datos
    push dword [irq_error_code]		; Codigo de error
    push dword [irq_number]			; Numero de interrupcion
    call isr_handler
    add esp, 3 * 4

    popa
    pop gs
    pop fs
    pop es
    pop ds
    add esp, 4		; Por el SS

    iret


extern idt_register		; Esta funcion registra en la IDT un nuevo handler

; Esta funcion es llamada desde idt_init() y se encarga de llamar a 
; la funcion idt_register() para registrar todos los handlers de interrupcion.

global isr_set_handlers

isr_set_handlers:

	push ebp
	mov ebp, esp
	push esi
	push edi
	push ebx

; Registro las excepciones e interrupciones

%assign i 0x0
%rep 48
    push dword isr_%+ i
    push i
    call idt_register
    add esp, 2 * 4
    %assign i (i + 1)
%endrep

; Registro la interrupcion de la syscall

    push dword isr_128
    push 0x80
    call idt_register
    add esp, 2 * 4

    pop ebx
    pop edi
    pop esi
    pop ebp
    ret
